#include "IMSession.h"
#include "IMLogic.h"
#include "mysql/QueryResult.h"
#include "IMSessionCache.h"

std::string im_generate_uuid()
{
    boost::uuids::random_generator generator;
    boost::uuids::uuid uuid = generator();
    return boost::uuids::to_string(uuid);
}

IMSession::IMSession(tcp::socket socket) : socket_(std::move(socket)), token_(im_generate_uuid())
{
}

void IMSession::start()
{
    IMSessionCache::getInstance()->add(token_, shared_from_this());
    do_read();
}

void IMSession::send(const msg_type &t, const char *data, const size_t &len)
{
    std::unique_ptr<boost::asio::streambuf> sb(new boost::asio::streambuf());
    std::ostream os(&(*sb));
    size_t header_length = sizeof(size_t) + sizeof(msg_type);
    size_t message_length = header_length + len;
    os.write((const char *)&message_length, sizeof(size_t));
    os.write((const char *)&t, sizeof(msg_type));
    if (len > 0)
        os.write(data, len);
    message_queue_.push(std::move(sb));
    do_write();
}

void IMSession::do_read()
{
    // auto self(shared_from_this()); // 有sessioncache不需要
    // boost::asio::async_read_some则会尽快返回。
    // 它将读取尽可能多的数据，但不会等待填满缓冲区。
    // 如果有可用的数据，async_read_some将立即返回，即使缓冲区还有剩余的空间。
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
                            [this](boost::system::error_code ec, std::size_t length)
                            {
                                // 头部是整个消息的长度
                                // 消息结构 4字节长度 + 消息类型 + 消息内容
                                if (ec)
                                {
                                    if (ec == boost::asio::error::eof)
                                    {
                                        // 连接已经断开
                                        LOG_I << "socket eof";
                                    }
                                    else
                                    {
                                        // 其他错误
                                        LOG_E << "socket error:" << ec.message();
                                    }
                                    do_close();
                                    return;
                                    // do_write(length);
                                }
                                else
                                {
                                    LOG_I << "socket read:" << length;
                                }
                                std::iostream ios(&sb_);
                                ios.write(data_, length);
                                // sb_.consume(10);
                                size_t header_length = 0;
                                while ((header_length = get_header_leagth(ios)) <= sb_.size())
                                {
                                    dev_message(ios);
                                    sb_.consume(header_length + sizeof(size_t));
                                }

                                do_read();
                            });
}

void IMSession::do_write()
{
    if (is_writing_)
        return;
    is_writing_ = true;
    // auto self(shared_from_this());// 有sessioncache不需要
    auto sb = std::move(message_queue_.front());
    boost::asio::async_write(socket_, boost::asio::buffer(sb->data(), sb->size()),
                             [this](boost::system::error_code ec, std::size_t /*length*/)
                             {
                                 is_writing_ = false;
                                 if (ec)
                                 {
                                     LOG_E << "socket write error:" << ec.message();
                                     do_close();
                                     return;
                                 }
                                 if (message_queue_.size() > 0)
                                     do_write();
                             });
}

inline void IMSession::do_close()
{
    boost::system::error_code ec;
    socket_.close(ec);
    IMSessionCache::getInstance()->remove(token_);
}

void IMSession::dev_message(std::iostream &ios)
{
    msg_type type = msg_type_unknown;
    ios.read((char *)&type, sizeof(msg_type));
    switch (type)
    {
    case msg_type_heartbeat:
        // 心跳包
        onHeartbeat(ios);
        break;
    case msg_type_register:
        // 注册
        onRegister(ios);
        break;
    case msg_type_login:
        // 登陆
        onLogin(ios);
        break;
    case msg_type_getofriendlist:
        // 获取好友列表
        onFriendList(ios);
        break;
    case msg_type_finduser:
        // 查找用户
        /* code */
        break;
    case msg_type_operatefriend:
        // 添加、删除等好友操作
        /* code */
        break;
    case msg_type_userstatuschange:
        // 用户信息改变通知
        /* code */
        break;
    case msg_type_updateuserinfo:
        // 更新用户信息
        /* code */
        break;
    case msg_type_modifypassword:
        // 修改登陆密码
        /* code */
        break;
    case msg_type_creategroup:
        // 创建群组
        /* code */
        break;
    case msg_type_getgroupmembers:
        // 获取群组成员列表
        /* code */
        break;
    case msg_type_chat:
        // 单聊消息
        /* code */
        break;
    case msg_type_multichat:
        // 群发消息
        /* code */
        break;
    case msg_type_kickuser:
        // 被踢下线
        /* code */
        break;
    case msg_type_updateteaminfo:
        // 更新用户好友分组信息
        /* code */
        break;
    case msg_type_modifyfriendmarkname:
        // 更新好友备注信息
        /* code */
        break;
    case msg_type_movefriendtootherteam:
        // 移动好友至
        /* code */
        break;
    default:
        LOG_W << "unknow msg type:" << type;
        break;
    }
}

void IMSession::onHeartbeat(std::iostream &ios)
{
    send(msg_type_heartbeat, nullptr, 0);
}

void IMSession::onRegister(std::iostream &ios)
{
    msg_c_s::registet msg;
    ios.read((char *)&msg, sizeof(msg_c_s::registet));
    LOG_I << "registet:" << msg.username << "," << msg.password << "," << msg.nickname;
    db_logic::Registet(msg, [this](unsigned int err)
                       { 
                        msg_s_c::registet msg;
                        msg.result  = err;
                        send(msg_type_register, (const char *)&msg, sizeof(msg_s_c::registet)); });
}

void IMSession::onLogin(std::iostream &ios)
{
    msg_c_s::login msg;
    ios.read((char *)&msg, sizeof(msg_c_s::login));
    LOG_I << "login:" << msg.username << "," << msg.password;
    db_logic::Login(msg, shared_from_this(), [this](unsigned int err)
                    { 
                        msg_s_c::login msg;
                        msg.result  = err;
                        std::strcpy(msg.token,token_.c_str());
                        send(msg_type_login, (const char *)&msg, sizeof(msg_s_c::login)); });
}

void IMSession::onFriendList(std::iostream &ios)
{
    auto u = IMUserManager::getInstance()->FindUser(token_);
    db_logic::GetFriends(u->getUid(), true);
}

void IMSession::onFinduser(std::iostream &ios)
{
    // TODO
}
